import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;

public class Test1 {
    //关于Exception我们分为受查异常和非受查异常
    //也叫做编译时异常和运行时异常

    //运行时异常/非受查异常有：
    //数组越界，空指针，算数异常
    //编译时异常/受查异常有：
    //CloneNotSupported等

    //运行时异常也是一种子类，继承于Exception
    //public class RuntimeException extends Exception {
    //}

    /*
    1. Throwable：是异常体系的顶层类，其派生出两个重要的子类, Error 和 Exception
    2. Error：指的是Java虚拟机无法解决的严重问题，比如：JVM的内部错误、资源耗尽等，典型代表：
    StackOverflowError和OutOfMemoryError，一旦发生回力乏术。
    3. Exception：异常产生后程序员可以通过代码进行处理，使程序继续执行。比如：感冒、发烧。我们平时所说
    的异常就是Exception。
     */


    //异常的处理：
    //1. LBYL: Look Before You Leap. 在操作之前就做充分的检查. 即：事前防御型
    //这个方法有较大的缺陷：正常流程和错误处理流程代码混在一起, 代码整体显的比较混乱。

    //2. EAFP: It's Easier to Ask Forgiveness than Permission. "事后获取原谅比事前获取许可更容易".
    //也就是先操作, 遇到问题再处理. 即：事后认错型
    //优势：正常流程和错误流程是分离开的, 程序员更关注正常流程，代码更清晰，容易理解代码

    //EAFP语法格式：
    /*
    try{
        执行可能出现异常的代码
    }catch(){
        匹配
    }finally{、
        执行资源的关闭
    }
     */


    //在Java中，异常处理主要的5个关键字：throw、try、catch、final、throws。

    //异常抛出，我们现在看到的都是自动抛出的异常，但是我们可以手动抛出异常
    //在Java中，可以借助throw关键字，抛出一个指定的异常对象，将错误信息告知给调用者。
    public static void main1(String[] args) throws CloneNotSupportedException{
        // throws CloneNotSupportedException一般放在方法的声明的地方
        int a = 0;
        if(a == 0){
            //抛出一个自定义异常！
            //throw new ArithmeticException("a == 0");
            //这个算数异常属于运行时异常，不是受查异常，可以不用处理，直接交给JVM来处理

            throw new CloneNotSupportedException("a == 0");//这是一个受查异常

            //所以抛出一个运行时异常是不需要进行处理的但是如果是一个编译时的异常，我们需要处理这个异常，最简单的方式是通过throws去处理
        }
    }
    /*
    1. throw必须写在方法体内部
    2. 抛 出的对象必须是Exception 或者 Exception 的子类对象
    3. 如果抛出的是 RunTimeException 或者 RunTimeException 的子类，则可以不用处理，直接交给JVM来处理
    4. 如果抛出的是编译时异常，用户必须处理，否则无法通过编译
    5. 异常一旦抛出，其后的代码就不会执行

     */

    public static void main2(String[] args) throws CloneNotSupportedException{
        test();//这个时候要让这个main方法来处理这个test方法，
        //我们也可以不去处理在main方法中继续声明这个异常,那么这个时候运行时，就是jvm调用main方法来给我们处理这个自定义抛出的异常
        /*//throws对异常并没有真正处理，而是将异常报告给抛出异常方法的调用者，由调用者处理。*/
    }

    public static void main(String[] args) {
        try {
            test();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        //这个时候用try catch来处理test方法的异常
    }
    public static void test() throws CloneNotSupportedException {
        int a = 0;
        if (a == 0) {
            //抛出一个自定义异常！
            throw new CloneNotSupportedException("a == 0");//这是一个受查异常
        }
        //throws是告诉方法的调用者，我抛出了一个异常，但是并没有处理掉这个异常
        //那么就是谁调用test方法谁处理了这个异常
    }

}
class Config{
    //1. throws必须跟在方法的参数列表之后
    //2. 声明的异常必须是 Exception 或者 Exception 的子类
    //3. 方法内部如果抛出了多个异常，throws之后必须跟多个异常类型，之间用逗号隔开，如果抛出多个异常类型
    //具有父子关系，直接声明父类即可。
    File file;
    // public void OpenConfig(String filename) throws IOException,FileNotFoundException{
    // FileNotFoundException 继承自 IOException
    public void openConfig(String filename) throws IOException{
        if(filename.endsWith(".ini")){
            throw new IOException("文件不是.ini文件");
        }

        if(filename.equals("config.ini")){
            throw new FileNotFoundException("配置文件名字不对");
        }
    }
    //打开文件
    public void readConfig(){

    }
    //4. 调用声明抛出异常的方法时，调用者必须对该异常进行处理，或者继续使用throws抛出
    public static void main(String[] args) throws IOException {
    Config config = new Config();
    config.openConfig("config.ini");
    }
}